The zoom box in the upper-right corner of the standard document window allows the user to alternate quickly between two window positions and sizes: the user state and the standard state.
The user state is the window size and location established by the user. If your application does not supply an initial user state, the user state is simply the size and location of the window when it was created, until the user resizes it.
The standard state is the window size and location that your application considers most convenient, considering the function of the document and the screen space available. In a word-processing application, for example, a standard-state window might show a full page, if possible, or a page of full width and as much length as fits on the screen. If the user changes the page size with the Page Setup command, the application might adjust the standard state to reflect the new page size. If your application does not define a standard state, the Window Manager automatically sets the standard state to the entire gray region on the main screen, minus a three-pixel border on all sides. (See Macintosh Human Interface Guidelines for a detailed description of how your application determines where to open and zoom windows.) The user cannot change a window's standard state . (The user and standard states are stored in a data structure of type WStateData whose handle appears in the dataHandle field of the window record.)
Listing 3 illustrates an application-defined procedure, DoZoomWindow , which an application might call when the user clicks the zoom box. Because the user might have moved the window to a different screen since it was last zoomed, the procedure first determines which screen contains the largest area of the window and then calculates the ideal window size for that screen before zooming the window.
The screen calculations in the DoZoomWindow procedure compare GDevice records stored in the device list. (If Color QuickDraw is not available, DoZoomWindow assumes that it's running on a computer with a single screen.)
PROCEDURE DoZoomWindow (thisWindow: windowPtr; zoomInOrOut: Integer);
VAR
gdNthDevice, gdZoomOnThisDevice: GDHandle;
savePort: GrafPtr;
windRect, zoomRect, theSect: Rect;
sectArea, greatestArea: LongInt;
wTitleHeight: Integer;
sectFlag: Boolean;
BEGIN
GetPort(savePort);
SetPort(thisWindow);
EraseRect(thisWindow^.portRect); {erase to avoid flicker}
IF zoomInOrOut = inZoomOut THEN {zooming to standard state}
BEGIN
IF NOT gColorQDAvailable THEN {assume a single screen and }
BEGIN { set standard state to full screen}
zoomRect := screenBits.bounds;
InsetRect(zoomRect, 4, 4);
WStateDataHandle(WindowPeek(thisWindow)^.dataHandle)^^.stdState
:= zoomRect;
END
ELSE {locate window on available screens}
BEGIN
windRect := thisWindow^.portRect;
LocalToGlobal(windRect.topLeft); {convert to global coordinates}
LocalToGlobal(windRect.botRight);
{calculate height of window's title bar}
wTitleHeight := windRect.top - 1 -
WindowPeek(thisWindow)^.strucRgn^^.rgnBBox.top;
windRect.top := windRect.top - wTitleHeight;
gdNthDevice := GetDeviceList; {get the first screen}
greatestArea := 0; {initialize area to 0}
{check window against all gdRects in gDevice list and remember }
{ which gdRect contains largest area of window}
WHILE gdNthDevice <> NIL DO
IF TestDeviceAttribute(gdNthDevice, screenDevice) THEN
IF TestDeviceAttribute(gdNthDevice, screenActive) THEN
BEGIN
{The SectRect function calculates the intersection }
{ of the window rectangle and this GDevice's boundary }
{ rectangle and returns TRUE if the rectangles intersect, }
{ FALSE if they don't.}
sectFlag := SectRect(windRect, gdNthDevice^^.gdRect,
theSect);
{determine which screen holds greatest window area}
{first, calculate area of rectangle on current screen}
WITH theSect DO
sectArea := LongInt(right - left) * (bottom - top);
IF sectArea > greatestArea THEN
BEGIN
greatestArea := sectArea; {set greatest area so far}
gdZoomOnThisDevice := gdNthDevice; {set zoom device}
END;
gdNthDevice := GetNextDevice(gdNthDevice); {get next }
END; {of WHILE} { GDevice record}
{if gdZoomOnThisDevice is on main device, allow for menu bar height}
IF gdZoomOnThisDevice = GetMainDevice THEN
wTitleHeight := wTitleHeight + GetMBarHeight;
WITH gdZoomOnThisDevice^^.gdRect DO {create the zoom rectangle}
BEGIN
{set the zoom rectangle to the full screen, minus window title }
{ height (and menu bar height if necessary), inset by 3 pixels}
SetRect(zoomRect, left + 3, top + wTitleHeight + 3,
right - 3, bottom - 3);
{If your application has a different "most useful" standard }
{ state, then size the zoom window accordingly.}
{set up the WStateData record for this window}
WStateDataHandle(WindowPeek(thisWindow)^.dataHandle)^^.stdState
:= zoomRect;
END;
END;
END; {of inZoomOut}
{if zoomInOrOut = inZoomIn, just let ZoomWindow zoom to user state}
{zoom the window frame}
ZoomWindow(thisWindow, zoomInOrOut, (thisWindow = FrontWindow));
MyResizeWindow(thisWindow); {application-defined window-sizing routine}
SetPort(savePort);
END; (of DoZoomWindow)
If the user is zooming the window to the standard state, DoZoomWindow calculates a new standard size and location based on the application's own considerations, the current location of the window, and the available screens. The DoZoomWindow procedure always places the standard state on the screen where the window is currently displayed or, if the window spans screens, on the screen containing the largest area of the window.
Listing 3 uses the QuickDraw routines GetDeviceList , TestDeviceAttribute , GetNextDevice , SectRect , and GetMainDevice to examine characteristics of the available screens as stored in GDevice records. Most of the code in Listing 3 is devoted to determining which screen should display the window in the standard state.
Never use the bounds field of a PixMap record to determine the size of the screen; instead use the value of the gdRect field of the GDevice record for the screen, as shown in Listing 3 .
After calculating the standard state, if necessary, DoZoomWindow calls the ZoomWindow procedure to redraw the window frame in the new size and location and then calls the application-defined procedure MyResizeWindow to redraw the window's content region. For more information on zooming and resizing windows, see the chapter "Window Manager" in Inside Macintosh: Macintosh Toolbox Essentials .